<?php

/**
 * @package mikrokosmos
 * swf mikrokosmos main classes
 * working start in 09.2k4
 * jaco@pixeldump.org
 */

if(!class_exists("MKTagHeader")){ class MKTagHeader {}}

/**
 * basic swf header
 */
class MKSwfHeader {

	var $swfFileName = "";
	var $signature = "";
	var $classVersion = "0.1.0";
	var $swfFileSize = 0;
	var $swfVersion = 0;
	var $stageWidth = 0;
	var $stageHeight = 0;
	var $fps = 0;
	var $frameCount = 1;
	var $backgroundColor = "";
	var $isCompressed = "";
	var $headerTags = array();

	// >= swf8
	var $fileAttributes;
	var $metadata;

	function MKSwfHeader($swfFileName = "",
							$swfVersion = 7,
							$stageWidth = 100,
							$stageHeight = 100,
							$fps = 12,
							$frameCount = 1,
							$backgroundColor = "#FFFFFF",
							$isCompressed = "no",
							$headerTags = array()) {

		$this->swfFileName = $swfFileName;
		$this->swfVersion = $swfVersion;
		$this->stageWidth = $stageWidth;
		$this->stageHeight = $stageHeight;
		$this->fps = $fps;
		$this->frameCount = $frameCount;
		$this->backgroundColor = $backgroundColor;
		$this->isCompressed = $isCompressed;
		$this->headerTags = $headerTags;

		if($swfVersion >= 8){
			$this->fileAttributes = new MKFileAttributes();
			//$this->metadata = new MKMetadata();
		}

		$this->signature = ($this->isCompressed == "no") ? "FWS" : "CWS";
	}

	//
	function set_swfFileName($swfFileName){ $this->swfFileName = $swfFileName; }
	function get_swfFileName(){ return $this->swfFileName; }

	//
	function set_signature($signature){ $this->signature = $signature; }
	function get_signature(){ return $this->signature; }

	//
	function set_swfFileSize($swfFileSize){ $this->swfFileSize = $swfFileSize; }
	function get_swfFileSize(){ return $this->swfFileSize; }

	//
	function set_swfVersion($swfVersion){ $this->swfVersion = $swfVersion; }
	function get_swfVersion(){ return $this->swfVersion; }

	//
	function set_stageWidth($stageWidth){ $this->stageWidth = $stageWidth; }
	function get_stageWidth(){ return $this->stageWidth; }

	//
	function set_stageHeight($stageHeight){ $this->stageHeight = $stageHeight; }
	function get_stageHeight(){ return $this->stageHeight; }

	//
	function set_stageSize($stageWidth = 550, $stageHeight = 400) {
		$this->set_stage_dimensions($stageWidth, $stageHeight);
	}

	//
	function set_stage_dimensions($stageWidth = 550, $stageHeight = 400){
		$this->stageWidth = $stageWidth;
		$this->stageHeight = $stageHeight;
	}

	//
	function set_fps($fps){ $this->fps = $fps; }
	function get_fps(){ return $this->fps; }

	// aliases of set/get fps
	function set_frameRate($fps) { $this->set_fps($fps); }
	function get_frameRate() { return $this->fps; }

	//
	function set_frameCount($frameCount){ $this->frameCount = $frameCount; }
	function get_frameCount(){ return $this->frameCount; }

	//
	function set_backgroundColor($backgroundColor){ $this->backgroundColor = $backgroundColor; }
	function get_backgroundColor(){ return $this->backgroundColor; }

	//
	function set_isCompressed($isCompressed) {
		if(is_bool($isCompressed)) $isCompressed = ($isCompressed) ? "yes" : "no";
		$this->isCompressed = strtolower($isCompressed);
	}
	function get_isCompressed(){ return $this->isCompressed; }

	//
	function set_headerTags($headerTags){ $this->headerTags = $headerTags; }
	function get_headerTags(){ return $this->headerTags; }


	// >= swf8
	function set_fileAttributes($mkfa){ $this->fileAttributes = $mkfa;	}
	function get_fileAttributes(){ return $this->fileAttributes; }

	// >= swf8
	function set_metadata($metadata){ $this->metadata = $metadata;	}
	function get_metadata(){ return $this->metadata; }

	//
	function set_AS3_flag($as3Flag) {
		$this->swfVersion = max($this->swfVersion, 9);
		if($this->fileAttributes == NULL) $this->fileAttributes = new MKFileAttributes();
		$this->fileAttributes->set_containsAS3(true);
	}

	//
	function fetch_assoc(){

		$ar = array();

		$ar["swfFileName"] = $this->swfFileName;
		$ar["swfFileSize"] = $this->swfFileSize;
		$ar["swfVersion"] = $this->swfVersion;
		$ar["stageWidth"] = $this->stageWidth;
		$ar["stageHeight"] = $this->stageHeight;
		$ar["fps"] = $this->fps;
		$ar["frameCount"] = $this->frameCount;
		$ar["backgroundColor"] = $this->backgroundColor;
		$ar["isCompressed"] = $this->isCompressed;

		if($this->swfVersion >= 8){
			//$ar["fileAttributes"] = $this->fileAttributes->fetch_assoc();
			//$ar["metadata"] = $this->metadata->fetch_assoc();
		}

		$ar["headerTags"] = array();

		foreach($this->headerTags as $ht)
			$ar["headerTags"][] = $ht->fetch_assoc();

		return $ar;
	}
}


/**
* frame object
* --- please doc members ---
*/
class SWFFrame {

	var $frameNumber;
	var $tagList = array();

	function SWFFrame($frameNumber){
		$this->frameNumber = $frameNumber;
	}

	function set_frameNumber($frameNumber){ $this->frameNumber = $frameNumber; }
	function get_frameNumber(){ return $this->frameNumber; }

	function set_tagList($tagList) { $this->tagList = $tagList; }
	function get_tagList(){ return $this->tagList; }

	function get_tagCount() { return count($this->tagList); }

	function add_tag($tagData = "", $tagHData = array()){
			/* $tagID, $tagType, $itemID = 0, $tagLength = 0, $offset = 0){ */

		$tagIndex = count($this->tagList);
		$this->tagList[$tagIndex] = new SWFTag($tagData, $tagHData);
		//$this->tagList[$tagIndex] = new SWFTag($tagID, $tagType, $itemID, $tagLength, $offset);
	}

	//
	function add_tag_data($binData, $tagIndex = -1){

		$flIndex = count($this->tagList) - 1;
		if($tagIndex != -1) $flIndex = $tagIndex;

		$this->tagList[$flIndex]->set_binData_b64Data($binData);
	}

	//
	function add_tag_buf($tagBuf, $tagIndex = -1){

		$flIndex = count($this->tagList) - 1;
		if($tagIndex != -1) $flIndex = $tagIndex;

		$this->tagList[$flIndex]->set_buf($tagBuf);
	}

	//
	function replace_tag($tagIndex, $swfTagObj){

		$this->tagList[$tagIndex] = $swfTagObj;
	}

	//
	function get_tagAt($tagIndex){

		$tCount = count($this->tagList);
		if($tCount <= $tagIndex) return false;
		return $this->tagList[$tagIndex];
	}

	//
	function frame_is_empty(){
		if(!count($this->tagList)) return true;
		return false;
	}
}

/**
* tag object
* --- please doc members ---
*/
class SWFTag extends MKTagHeader {

	var $tagData = "";
	//var $tagID	 = 0;
	//var $tagType = "";
	//var $itemID  = -1;
	//var $tagLength = 0;
	//var $offset  = 0;
	var $tagHDbuf = "";
	var $tagBody = "";
	var $b64Data = "";

	// the constructor
	function SWFTag($tagData = "", $tagHData = array(), $offset = 0){

		if($offset) $this->offset = $offset;

		if(strlen($tagData)){

			$this->tagData = $tagData;
			$this->tagHDBuf = substr($tagData, 0, 10);
			parent::MKTagHeader($this->tagHDbuf);
			$this->tagBody = substr($tagData, $this->tagSL);
		}

		if(count($tagHData)){
			$this->tagID	 = $tagHData["tagID"];
			$this->tagType 	 = $tagHData["tagType"];
			$this->itemID 	 = $tagHData["itemID"];
			$this->tagLength = $tagHData["tagLength"];
			$this->tagHDbuf  = $tagHData["buf"];
			if(isset($tagHData["tagSL"])) $this->tagSL = $tagHData["tagSL"];
			if(isset($tagHData["offset"])) $this->offset = $tagHData["offset"];
		}
	}

	//
	function set_buf($buf) { $this->tagData = $buf; }
	function get_buf() { return $this->tagData; }

	//
	function set_tagID($tagID){ $this->tagID = $tagID; }
	function get_tagID(){ return $this->tagID; }

	//
	function set_tagType($tagType){ $this->tagType = $tagType; }
	function get_tagType(){ return $this->tagType; }

	//
	function set_itemID($itemID){ $this->itemID = $itemID; }
	function get_itemID(){ return $this->itemID; }

	//
	function set_tagLength($tagLength){ $this->tagLength = $tagLength; }
	function get_tagLength(){ return $this->tagLength; }

	//
	function set_binData_b64Data($binData){
		$this->set_b64Data(base64_encode($binData));
	}

	function get_binData(){ return base64_decode($this->b64Data); }

	//
	function set_b64Data($b64Data){ $this->b64Data = $b64Data; }
	function get_b64Data(){ return $this->b64Data; }

	//
	function set_offset($offset){ $this->offset = $offset; }
	function get_offset(){ return $this->offset; }

	//
	function set_tagBody($tagBody = ""){

		if(strlen($tagBody)){
			$this->tagBody = $tagBody;
		}
		else if(strlen($this->tagData)){

			$this->tagHDBuf = substr($this->tagData, 0, 10);
			parent::MKTagHeader($this->tagHDbuf);
			$this->tagBody = substr($this->tagData, $this->tagSL);
		}
	}
	function get_tagBody(){ return substr($this->tagData, $this->tagSL); }

	function get_tagContent(){
		$ofst = has_itemID($this->tagID) ? 2 : 0;
		return substr($this->tagData, $this->tagSL + $ofst);
	}


	//
	function load_from_file($tagFN, $tagDir = SERVER_MKTAGS) {
		$tagPath = $tagDir .$tagFN;
		$fin = fopen($tagPath, "rb");
		$tagData = fread($fin, filesize($tagPath));
		$this->SWFTag($tagData);
		return $tagData;
	}

	//
	function save_to_file($tagFN = "", $tagDir = SERVER_MKTAGS, $frameNumber = 0, $progressiveItem = 0) {
		$td = $this->fetch_assoc();

		if(!strlen($tagFN)) {
			$tagFN = "";
			if($frameNumber > 0)
				$tagFN .= "f" .str_pad($frameNumber, 5, "0", STR_PAD_LEFT) ."_";

			if($progressiveItem > 0)
				$tagFN .= "p" .str_pad($progressiveItem, 4, "0", STR_PAD_LEFT) ."_";

			$tagFN .= "t" .str_pad($td["tagID"], 3, "0", STR_PAD_LEFT) ."_";

			if(has_itemID($td["tagID"])) $tagFN .=  "i" .str_pad($td["itemID"], 3, "0", STR_PAD_LEFT) ."_";
			$tagFN .=  "o" .$td["offset"] .".tag";
		}

		$tagPath = $tagDir .$tagFN;
		$fout = fopen($tagPath, "wb");
		fwrite($fout, $this->tagData, strlen($this->tagData));
		fflush($fout);
		fclose($fout);
	}

	// alias of constructor
	function set_tagData($tagData){ $this->SWFTag($tagData); }

	function get_tagData(){

		if(strlen($this->tagData)) return $this->tagData;

		if(strlen($this->tagHDbuf) && strlen($this->tagBody))
			return $this->tagHDbuf .$this->tagBody;

		return -1; // no tagData is available
	}

	function fetch_assoc(){

		$std = array();

		$std["tagID"] = $this->tagID;
		$std["tagType"] = $this->tagType;
		$std["itemID"] = $this->itemID;
		$std["tagLength"] = $this->tagLength;
		$std["offset"] = $this->offset;
		if(strlen($this->tagHDbuf)) $std["tagHDbuf"] = $this->tagHDbuf;
		if(strlen($this->tagBody)) $std["tagBody"] = $this->tagBody;

		return $std;
	}

	function fetch_xml($includeHeader = true, $tabLevel = 0, $nodeName = "tag", $includeHexData = false){

		if(!strlen($nodeName)) $nodeName = "tag";

		$xmlStr = $includeHeader ? XML_HEADER : "";
		$pfx = get_xml_indent_row(++$tabLevel);
		$xmlStr .= $pfx ."<" .$nodeName ." ";
		$xmlStr .= "code=\"" .$this->tagID ."\" ";
		$xmlStr .= "type=\"" .$this->tagType ."\" ";

		if(has_itemID($this->tagID)) $xmlStr .= "id=\"" .$this->itemID ."\" ";

		//if($this->itemID) $xmlStr .= "id=\"" .$this->itemID ."\" ";

		$xmlStr .= "bodyLength=\"" .$this->tagLength ."\" ";

		if($this->tagLength < 63 && $this->tagSL > 2) $xmlStr .= "recordHeader=\"long\" ";
		if($this->offset) $xmlStr .= "offset=\"" .$this->offset ."\" ";

		$xmlStr .= ">";

		if(($includeHexData || $this->tagType == "DoActionTag" || !is_supported_tag($this->tagID)) && strlen($this->tagBody)){
			$pfx = get_xml_indent_row(++$tabLevel);
			$xmlStr .= $pfx ."<hexData>";
			$xmlStr .= hex_dump($this->tagBody, true);
			$xmlStr .= $pfx ."</hexData>";
			$pfx = get_xml_indent_row(--$tabLevel);
		}

		$xmlStr .= $pfx ."</" .$nodeName .">";

		return $xmlStr;
	}
}


/**
 * basic bitmap class
 * -- please complete doc --
 */
class BitmapItem {

	var $bitmapID;
	var $bitmapType;
	var $bitmapWidth;
	var $bitmapHeight;
	var $bitDepth;
	var $rawData;
	var $jpegTable;
	var $jpegData;
	var $rgbData;
	var $alphaData;
	var $colorTable;
	var $swfFileName;
	var $pixelData;
	var $frameIndex;
	var $jpegTableFileName;
	var $binData;
	var $imageDir = SERVER_MKIMGS;		// working image source base path
	var $alphaImageDir = SERVER_MKIMGS; // working alpha image source base path

	var $imageFN;						// source image file
	var $alphaImageFN;					// source alpha image file


	function BitmapItem($bitmapID 		= 1,
						$bitmapType 	= "",
						$bitmapWidth 	= 0,
						$bitmapHeight 	= 0,
						$bitDepth	 	= 0,
						$rawData 		= "",
						$jpegTable 		= "",
						$jpegData 		= "",
						$rgbData 		= "",
						$alphaData 		= "",
						$pixelData 		= "",
						$colorTable 	= "",
						$swfFileName 	= "",
						$frameIndex 	= 1){

		$this->bitmapID   = $bitmapID;

		$this->bitmapType   = $bitmapType;
		$this->bitmapWidth  = $bitmapWidth;
		$this->bitmapHeight = $bitmapHeight;
		$this->bitDepth     = $bitDepth;
		$this->frameIndex   = $frameIndex;


		if(strlen($rawData)) $this->rawData = $rawData;
		if(strlen($jpegData)) $this->jpegData = $jpegData;
		if(strlen($rgbData)) $this->rgbData = $rgbData;
		if(strlen($alphaData)) $this->alphaData = $alphaData;
		if(strlen($pixelData)) $this->pixelData = $pixelData;
		if(strlen($colorTable)) $this->colorTable = $colorTable;

		if(strlen($swfFileName)){
			$this->swfFileName = $swfFileName;
			$this->set_imageFileNames();	// sets imageFileName & alphaImageFilename
		}

		if(strlen($jpegTable)){
			$this->jpegTable = $jpegTable;
			$this->save_image();
		}
	}

	function set_bitmapID($bitmapID){ $this->bitmapID = $bitmapID; }
	function get_bitmapID(){ return $this->bitmapID; }

	function set_bitmapType($bitmapType){ $this->bitmapType = $bitmapType; }
	function get_bitmapType(){ return $this->bitmapType; }

	function set_bitmapWidth($bitmapWidth){ $this->bitmapWidth = $bitmapWidth; }
	function get_bitmapWidth(){ return $this->bitmapWidth; }

	function set_imageWidth($imageWidth){ $this->bitmapWidth = $imageWidth; }
	function get_imageWidth(){ return $this->bitmapWidth; }

	function set_bitmapHeight($bitmapHeight){ $this->bitmapHeight = $bitmapHeight; }
	function get_bitmapHeight(){ return $this->bitmapHeight; }

	function set_imageHeight($imageHeight){ $this->bitmapHeight = $imageHeight; }
	function get_imageHeight(){ return $this->bitmapHeight; }

	function set_bitDepth($bitDepth){ $this->bitDepth = $bitDepth; }
	function get_bitDepth(){ return $this->bitDepth; }

	function set_rawData($rawData){ $this->rawData = $rawData; }
	function get_rawData(){ return $this->rawData; }

	function set_jpegData($jpegData){ $this->jpegData = $jpegData; }
	function get_jpegData(){ return $this->jpegData; }

	function set_rgbData($rgbData){ $this->rgbData = $rgbData; }
	function get_rgbData(){ return $this->rgbData; }

	function set_alphaData($alphaData){ $this->alphaData = $alphaData; }
	function get_alphaData(){ return $this->alphaData; }

	function set_colorTable($colorTable){ $this->colorTable = $colorTable; }
	function get_colorTable(){ return $this->colorTable; }

	function set_pixelData($pixelData){ $this->pixelData = $pixelData; }
	function get_pixelData(){ return $this->pixelData; }

	function set_frameIndex($frameIndex){ $this->frameIndex = $frameIndex; }
	function get_frameIndex(){ return $this->frameIndex; }

	function set_swfFileName($swfFileName){ $this->swfFileName = $swfFileName; }
	function get_swfFileName(){ return $this->swfFileName; }

	function hasAlpha(){
		if(strlen($this->alphaData)) return true;
		return false;
	}

	//
	function set_imageFileNames(){
		$this->imageFileName = get_imageFileName($this->swfFileName,
												$this->frameIndex,
												$this->bitmapID);

		$this->alphaImageFileName = $this->imageFileName ."_a.png";

		$ext = get_image_ext($this->bitmapType);

		$this->imageFileName = $this->imageFileName ."." .$ext;
	}

	//
	function set_imageFileName($imageFileName){ $this->imageFileName = $imageFileName; }
	function get_imageFileName(){ return $this->imageFileName; }

	//
	function get_jpegTableImageFileName(){ return $this->jpegTableImageFileName; }

	//
	function get_alphaImageFileName(){ return $this->alphaImageFileName; }

	//
	function set_binData($binData){ $this->binData = $binData; }
	function get_binData(){ return $this->binData; }


	//
	function update_binData($quality = 100){
		/* TO DO */
		return $this->binData;
	}

	//
	function create_from_file($imageFN, $imageDir = SERVER_MKIMAGES, $jpegQuality = 100){

		$imagePath = $imageDir .$imageFN;

		$this->imageFileName = $imageFN;
		$this->imageDir = $imageDir;
		$ext = substr($imagePath, -3);

		$bmAr = array();

		if($ext == "jpg"){
			$bmAr = write_bitmapTag_jpeg("DefineBitsJPEG2",
										$this->bitmapID,
										$imagePath,
										"",
										$jpegQuality,
										true);
		}
		else if($ext == "png"){
			$bmAr = write_bitmapTag_png($this->bitmapID,
										$imagePath, true);
		}

		$this->binData = $bmAr["binData"];
		$this->bitmapWidth = $bmAr["bitmapWidth"];
		$this->bitmapHeight = $bmAr["bitmapHeight"];

		return $this->binData;
	}

	//
	function set_image_source($imageFN, $imageDir = SERVER_MKIMAGES){
		$this->imageFN = $imageFN;
		$this->imageDir = $imageDir;

		$imagePath = $imageDir .$imageFN;

		if(!file_exists($imagePath)) {
			$this->imageFN = "";
			$this->imageDir = SERVER_MKIMAGES;
		}
		else {
			$bs = getimagesize($imagePath);
			$this->bitmapWidth = $bs[0];
			$this->bitmapHeight = $bs[1];
		}
	}


	//
	function load_alpha_from_file($imageFN, $imageDir = SERVER_MKIMAGES){
		$imgAlphaPath = $imageDir .$imageFN;

		if(!file_exists($imgAlphaPath)) return "";

		$this->alphaData = read_image_as_alpha($imgAlphaPath);
	}

	//
	function update_lossy_tagData($quality = 80){
		/* TODO */
		$imagePath = $this->imageDir .$this->imageFN;

		if(!file_exists($imagePath)) return "";		// fails if not exists a valid source image
		if(!strlen($this->alphaData)) return "";		// fails if there are no alphaData

		$this->binData = write_bitmapTag_jpeg(JPEG_ALPHA, $this->bitmapID, $imagePath,
											$this->alphaData, $quality, false);

		return $this->binData;
	}

	//
	function save_image(){

		$pngout = SERVER_MKTMP .$this->imageFileName;
		$jpegData = "";

		if($this->bitmapType == IMAGE_LOSSLESS){ // lossless image

			if($this->bitDepth == IMG_LS_PALETTE_8 ) {

				save_lossless_8 ($pngout,
								$this->pixelData, $this->colorTable,
								$this->bitmapWidth, $this->bitmapHeight);
			}
			else if($this->bitDepth == IMG_LS_PALETTE_15) {

				save_lossless_rgb($pngout,
									$this->rgbData,
									$this->bitmapWidth, $this->bitmapHeight);
			}
			else if($this->bitDepth == IMG_LS_RGB) { // lossless rb image

				save_lossless_rgb($pngout,
									$this->rgbData,
									$this->bitmapWidth, $this->bitmapHeight);
			}
		}
		else if($this->bitmapType == IMAGE_LOSSLESS_ALPHA){

			if($this->bitDepth == IMG_LS_PALETTE_8_ALPHA) {

				save_lossless_8_alpha($pngout,
										$this->pixelData, $this->colorTable, $this->alphaData,
										$this->bitmapWidth, $this->bitmapHeight);
			}
			else if($this->bitDepth == IMG_LS_RGB_ALPHA){

				save_lossless_rgb_alpha($pngout,
										$this->rgbData, $this->alphaData,
										$this->bitmapWidth, $this->bitmapHeight);
			}
		}
		else {	// lossy image
			if($this->bitmapType == JPEG_ALPHA){						// jpeg data with alpha

				save_jpeg_alpha($pngout,
								$this->jpegData, $this->alphaData,
								$this->bitmapWidth, $this->bitmapHeight);
				return;
			}
			else if($this->bitmapType == JPEG2){
				$jpegData = $this->jpegData;
			}
			else if($this->bitmapType == JPEG){ // only jpegImage
				$jpegData = $this->retrieve_jpegTable();
			}
			else if($this->bitmapType == JPEG_TABLE){ // jpegTable only

					// save jpegTable and return
					$this->jpegTableFileName = get_imageFileName($this->swfFileName) ."_jt.bin";

					$jto = fopen(SERVER_MKTMP .$this->jpegTableFileName, "wb");
					fwrite($jto, $this->jpegTable, strlen($this->jpegTable) - 2);
					fclose($jto);
					return;
			}

			$jpgout = SERVER_MKTMP .$this->imageFileName;
			$jo = fopen($jpgout, "wb");
			fwrite($jo, $jpegData, strlen($jpegData));
			fclose($jo);
		}
	}


	//
	function save_alpha(){

		if(!strlen($this->alphaData)) return;

		$pngout = SERVER_MKTMP .$this->alphaImageFileName;

		if($this->bitmapType == JPEG_ALPHA){

			save_gray_alpha($pngout,
							$this->alphaData,
							$this->bitmapWidth, $this->bitmapHeight);
		}
		else if($this->bitmapType == IMAGE_LOSSLESS_ALPHA){

			if($this->bitDepth == IMG_LS_PALETTE_8_ALPHA){

				save_index_alpha($pngout,
								$this->alphaData, $this->pixelData,
								$this->bitmapWidth, $this->bitmapHeight);
			}
			else if($this->bitDepth == IMG_LS_RGB_ALPHA){

				save_gray_alpha($pngout,
								$this->alphaData,
								$this->bitmapWidth, $this->bitmapHeight);
			}
		}
	}


	//
	function retrieve_jpegTable(){

		$jpegTable = "";
		$jpegData = "";

		if(strlen($this->jpegTable)){

			$jpegTable = $this->jpegTable;
		}
		else {

			// check if there is saved jpegTable data
			// else ends silently
			$this->jpegTableFileName = get_imageFileName($this->swfFileName) ."_jt.bin";

			if(!file_exists(SERVER_MKTMP .$this->jpegTableFileName)){
				return;
			}

			$jtPath = SERVER_MKTMP .$this->jpegTableFileName;
			$jti = fopen($jtPath, "r");
			$jpegTable = fread($jti, filesize($jtPath));
			fclose($jti);
		}

		$jpegData = $jpegTable .substr($this->jpegData, 2);
		$this->jpegTable = "";
		$this->jpegData = $jpegData;
		$this->bitmapType = JPEG2;

		return $this->jpegData;
	}
}

/**
 * used to store bitmap item data
 */
class BitmapSerializer {

	var $serializedFileName;
	var $biInstance;

	function BitmapSerializer($biInstance){

		$this->set_serializedFileName($biInstance->get_imageFileName());
		$this->set_biInstance($biInstance);
		$this->serialize_class();
	}

	function set_serializedFileName($bifn){
		 $this->serializedFileName = substr($bifn, 0, strlen($bifn) - 4) ."_ser.mks";
	}

	function get_serializedFileName() { return $this->serializedFileName; }

	function set_biInstance($biInstance)  { $this->biInstance = $biInstance; }
	function get_biInstance()  { return $this->biInstance; }

	function serialize_class(){

		$bsPath = SERVER_MKTMP .$this->serializedFileName;

		$str = serialize($this->biInstance);

		$fo = fopen($bsPath, "wb");
		fwrite($fo, $str, strlen($str));
		fclose($fo);
	}
}

/**
 * unserialize bitmap item data
 */
class BitmapUnserializer {

	var $serializedFileName;
	var $swfFileName;
	var $frameIndex;
	var $bitmapID;

	function BitmapUnserializer($swfFileName = "", $fn = 1, $bid = 0){

		if(strlen($swfFileName)){
			$this->swfFileName = $swfFileName;;
			$this->frameIndex = $fn;
			$this->bitmapID = $bid;
			$this->set_serializedFileName($swfFileName, $fn, $bid);
		}
	}

	function set_swfFileName($swfFileName){ $this->swfFileName = $swfFileName; }
	function get_swfFileName(){ return $this->swfFileName; }

	function set_frameIndex($frameIndex){ $this->frameIndex = $frameIndex; }
	function get_frameIndex() { return $this->frameIndex; }

	function set_bitmapID($bitmapID) { $this->bitmapID = $bitmapID; }
	function get_bitmapID() { return $this->bitmapID; }

	function b64decode_frameList(){
		$fList = array();

		foreach($this->frameList as $frame){
		}

		return $fList();
	}

	function set_serializedFileName($swfFileName, $fn, $bid){

		$imageFileName = get_imageFileName($this->swfFileName,
											$this->frameIndex,
											$this->bitmapID);

		$this->serializedFileName = $imageFileName ."_ser.mks";
	}

	function unserialize_class(){
		$sfPath = SERVER_MKTMP .$this->serializedFileName;
		//$bi = new BitmapItem(0, 0, 0, 0);

		$fin = fopen($sfPath, "rb");
		$str = fread($fin, filesize($sfPath));
		fclose($fin);

		$bi = unserialize($str);

		return $bi;
	}
}


/**
 * gets an overview on some features of given swf
 * --- please doc methods
 */

class MKSwfOverview {

	var $swfFileName = "";
	var $signature = "";
	var $swfFileSize = 0;
	var $swfInflatedFileSize = 0;
	var $swfVersion = 0;
	var $isCompressed = "";

	var $swfWorkingDir;
	var $swfHeaderBuf = "";

	function MKSwfOverview($swfFileName = "", $swfWorkingDir = ""){

		$this->swfWorkingDir = SERVER_MKFLASH;

		if(strlen($swfWorkingDir))
			$this->swfWorkingDir = $swfWorkingDir;

		if(strlen($swfFileName)){

			$this->swfFileName = $swfFileName;
			$this->get_overview();
		}
	}

	function set_swfFileName($swfFileName){ $this->swfFileName = $swfFileName; }
	function get_swfFileName(){ return $this->swfFileName; }

	function set_signature($signature){ $this->signature = $signature; }
	function get_signature(){ return $this->signature; }

	function set_swfFileSize($swfFileSize){ $this->swfFileSize = $swfFileSize; }
	function get_swfFileSize(){ return $this->swfFileSize; }

	function set_swfInflatedFileSize($swfUncompressedFileSize){ $this->swfInflatedFileSize = $swfUncompressedFileSize; }
	function get_swfInflatedFileSize(){ return $this->swfInflatedFileSize; }

	function set_swfVersion($swfVersion){ $this->swfVersion = $swfVersion; }
	function get_swfVersion(){ return $this->swfVersion; }

	function set_isCompressed($isCompressed){ $this->isCompressed = $isCompressed; }
	function get_isCompressed(){ return $this->isCompressed; }

	function set_swfWorkingDir($swfWorkingDir){ $this->swfWorkingDir = $swfWorkingDir; }
	function get_swfWorkingDir(){ return $this->swfWorkingDir; }

	function set_swfHeaderBuf($swfHeaderBuf){ $this->swfHeaderBuf = $swfHeaderBuf; }
	function get_swfHeaderBuf(){ return $this->swfHeaderBuf; }

	function get_overview(){

		if(!strlen($this->swfFileName)) return;

		$swfPath = $this->swfWorkingDir .$this->swfFileName;
		$fin = fopen($swfPath, "rb");
		$he = fread($fin, 8);
		$this->swfHeaderBuf = $he;
		fclose($fin);

		$this->signature = substr($he, 0, 3);
		$this->swfVersion = ui8dec($he[3]);
		$this->swfFileSize = filesize($swfPath);

		$this->isCompressed = ($he[0] == "C") ? "yes" : "no";

		if($this->isCompressed == "yes")
		  $this->swfInflatedFileSize = ui32dec(substr($he, 4));
	}

	function fetch_assoc(){
		$soad = array();
		$soad["swfFileName"] = $this->swfFileName;
		$soad["signature"] = $this->signature;
		$soad["swfFileSize"] = $this->swfFileSize;
		$soad["swfInflatedFileSize"] = $this->swfInflatedFileSize;
		$soad["swfVersion"] = $this->swfVersion;
		$soad["isCompressed"] = $this->isCompressed;

		return $soad;
	}

	//
	function fetch_xml(){
	}
}

// remember, look at config.inc.php
/**
* gets info on a given swf file, veryfing if it is a valid swf
* ++++ please doc methods ++++
*/
class MKSwfInfo extends MKSwfHeader {

	var $classStatus = INSTANCE_EMPTY;
	var $swfWorkingDir;
	var $tmpFileName = "";
	var $startBody = 0;		// byte offset where start to retrieve tags
	var $nocache;
	var $rawBody = "";

	var $swfHeaderBuf = "";
	var $rawHeaderData = "";

	var $xmlHeader = "<?xml version=\"1.0\"?>";
	var $xmlTagName = "MKSwfInfo";

	var $bgTagIndex = -1;

	// main construction, if a filename is given gets info immediatly
	function MKSwfInfo($fin = "", $swfWorkingDir = "", $nocache = true){

		$this->swfWorkingDir = SERVER_MKFLASH;
		if(strlen($swfWorkingDir)) $this->swfWorkingDir = $swfWorkingDir;

		$this->tmpFileName = get_tmpFileName();
		$this->nocache = $nocache;

		if(strlen($fin)){

			if(!file_exists($this->swfWorkingDir)) return STAT_FILENOTFOUND;

			$this->swfFileName = $fin;
			$this->swf_info();
		}
	}

	//
	function set_swfWorkingDir($swfWorkingDir){ $this->swfWorkingDir = $swfWorkingDir; }
	function get_swfWorkingDir(){ return $this->swfWorkingDir; }

	function set_rawBody($rawBody){ $this->rawBody = $rawBody; }
	function get_rawBody(){ return $this->rawBody; }

	// override superclass
	function set_backgrounColor($bgColor){
		if($this->bgTagIndex == -1){
			$tagObj = new MKSetBackgroundColor("", $bgColor);
			$this->headerTags[] = $tagObj;
			$this->bgTagIndex = count($this->headerTags) - 1;
			$this->backgroundColor = get_color_string($tagObj->get_backgroundColor());
		}
		else {
			$this->headerTags[$this->bgTagIndex]->set_backgroundColor($bgColor);
		}
	}

	// alreay available in superclass
	//function get_backgroundColor() { return $this->backgroundColor; }

	//
	function swf_check_classStatus(){
		if($this->classStatus == INSTANCE_EMPTY || $this->classStatus == INSTANCE_PENDING)
			return "error_code=" .$this->classStatus;
	}

	// check if it is a valid swf
	// and get info
	function swf_info(){

		$filePath = $this->swfWorkingDir .$this->swfFileName;
		if(!file_exists($filePath)) return STAT_FILENOTFOUND;

		$swfin = fopen($filePath, "rb");
		$swfF8 = fread($swfin, 8);
		$this->swfHeaderBuf = $swfF8;
		$this->signature = substr($swfF8, 0, 3);

		if($this->signature != "FWS" && $this->signature != "CWS")
			return STAT_NOTASWF;

		$this->swfFileSize = filesize($filePath);

		$storedFileSize = ui32dec(substr($swfF8, 4, 4));

		if($this->signature[0] == "F" && $storedFileSize != $this->swfFileSize)
			return STAT_NOTASWF;

		$this->swfVersion = ui8dec($swfF8[3]);

		// this will be useful when reading
		// further data, if needed, other classes
		// or functions can get access
		// via get_global_swfVersion
		set_global_swfVersion($this->swfVersion);

		$tf = fopen($this->tmpFileName, "wb");
		$chunkTH = min(2048, $this->swfFileSize - 8);

		if($this->signature[0] == "C"){

			$this->isCompressed = "yes";
			fseek($swfin, 8, SEEK_SET);
			//$swfData = fread($swfin, filesize($this->swfWorkingDir .$this->swfFileName));
			//$binData = gzuncompress(substr($swfData, 8));
			$gzData = fread($swfin, $this->swfFileSize - 8);

			/*
			$fout = fopen(SERVER_MKTMP ."gzdata.gz", "wb");
			fwrite($fout, $gzData, strlen($gzData));
			fclose($fout);
			*/

			// take care, not always gzuncompress is successful :(
			$binData = gzuncompress($gzData);

			$chunkTH = min(8192, strlen($binData) - 8);
			$tailHeader = substr($binData, 0, $chunkTH);
		}
		else{
			$this->isCompressed = "no";
			$tailHeader = fread($swfin, $chunkTH);
			fseek($swfin, 8, SEEK_SET);
			$binData = fread($swfin, $this->swfFileSize - 8);
		}

		fclose($swfin);

		//$this->startBody = $this->get_tailHeader_data($tailHeader);
		$this->startBody = $this->get_header_data($tailHeader);

		$this->rawBody = substr($binData, $this->startBody);
		$this->rawHeaderData = substr($binData, 0, $this->startBody);

		fwrite($tf, $this->rawBody, strlen($this->rawBody));
		fflush($tf);
		fclose($tf);

		if($this->nocache) $this->clearcache();

		$this->classStatus = INSTANCE_READY;
	}

	//
	function get_header_data($hdBuf = ""){

		$rect = new MKRect(substr($hdBuf, 0, MAX_RECT_LENGTH));
		$rd = $rect->fetch_assoc(false);

		$this->stageWidth = $rd["xmax"] - $rd["xmin"];
		$this->stageHeight = $rd["ymax"] - $rd["ymin"];

		$cursor = $rd["rectLength"] + 1;
		$this->fps = ui8dec($hdBuf[$cursor]);
		$cursor++;
		$this->frameCount = ui16dec(substr($hdBuf, $cursor, 2));
		$cursor += 2;

		$tagObj = NULL;

		for( ; ; ) {

			$thd = read_tag_header_data(substr($hdBuf, $cursor, 10));
			if(is_headerTag($thd["tagID"])){
				$tagName = get_tagName($thd["tagID"]);
				$tdLength = $thd["tagSL"] + $thd["tagLength"];
				$tagData = substr($hdBuf, $cursor, $tdLength);

				if($tagName == "EnableDebugger2") $tagName = "EnableDebugger";

				$evStr = "\$tagObj = new MK" .$tagName ."(\$tagData);";
				eval($evStr);

				if($tagName == "SetBackgroundColor")
					$this->backgroundColor = get_color_string($tagObj->get_backgroundColor());

				$this->headerTags[] = $tagObj;
				$cursor += $tdLength;
			}
			else break;
		}

		return $cursor;
	}

	function dump_headerData($swfHDataFN = "", $dataDir = SERVER_MKTAGS) {
		if(!strlen($swfHDataFN)){
			$swfHDataFN = substr($this->swfFileName, 0, -4) ."_header_" .mktime() .".bin";
		}

		$dataPath = $dataDir .$swfHDataFN;
		$fout = fopen($dataPath, "wb");
		fwrite($fout, $this->swfHeaderBuf, 8);
		fwrite($fout, $this->rawHeaderData, strlen($this->rawHeaderData));
		fflush($fout);
		fclose($fout);
	}

	//
	function set_xmlTagName($tagName){
		$this->xmlTagName = $tagName;
	}

	//
	function set_xmlHeader($xmlHeader){
		$this->xmlHeader = $xmlHeader;
	}

	//
	function clearcache(){
		if(!strlen($this->tmpFileName)) return;
		if(!file_exists($this->tmpFileName)) return;
		unlink($this->tmpFileName);
		$this->set_tmpFileName("");
	}

	//
	function set_tmpFileName($tmpFileName){ $this->tmpFileName = $tmpFileName; }

	//
	function fetch_assoc(){

		//$this->swf_check_classStatus();
		$ar = array();

		$ar["swfFileName"] = $this->swfFileName;
		$ar["swfFileSize"] = $this->swfFileSize;
		$ar["swfVersion"] = $this->swfVersion;
		$ar["stageWidth"] = $this->stageWidth;
		$ar["stageHeight"] = $this->stageHeight;
		$ar["fps"] = $this->fps;
		$ar["frameCount"] = $this->frameCount;
		$ar["backgroundColor"] = $this->backgroundColor;
		$ar["isCompressed"] = $this->isCompressed;

		$ar["headerTags"] = array();

		foreach($this->headerTags as $ht)
			$ar["headerTags"][] = $ht->fetch_assoc();

		return $ar;
	}

	// options
	// info: build a complete xml set with swf info
	// tag: build a xml header without closing tag MKSwfInfo
	// item: useful when requesting info for swf listing
	function fetch_xml($includeHeader = true, $tabLevel = 0, $nodeName = "swfHeader", $closeXML = false){

		//$this->swf_check_classStatus();

		$xmlStr = $includeHeader ? XML_HEADER : "";
		$pfx = get_xml_indent_row(++$tabLevel);

		if(strlen($nodeName)) $xmlStr .= $pfx ."<" .$nodeName;
		else $xmlStr .= $pfx ."<" .$this->xmlTagName;
		$xmlStr .= " swfFileName=\"". $this->swfFileName ."\" ";
		$xmlStr .= "swfFileSize=\"" .$this->swfFileSize ."\" ";
		$xmlStr .= "swfVersion=\"" .$this->swfVersion ."\" ";
		$xmlStr .= "stageWidth=\"" .$this->stageWidth ."\" ";
		$xmlStr .= "stageHeight=\"" .$this->stageHeight ."\" ";
		$xmlStr .= "fps=\"" .$this->fps ."\" ";
		$xmlStr .= "frameCount=\"" .$this->frameCount ."\" ";
		$xmlStr .= "isCompressed=\"" .$this->isCompressed ."\" ";

		if(!$closeXML) $xmlStr .= "/";

		$xmlStr .= ">\r\n";

		foreach($this->headerTags as $ht){
			$xmlStr .= $ht->fetch_xml(false, $tabLevel);
		}

		if($closeXML) $xmlStr .= "</" .$nodeName .">\r\n";

		return $xmlStr;
	}

	// this is an alias of fetch_assoc();
	function swf_fetch_assoc(){ return $this->fetch_assoc(); }

	// this is an alias of fetch_xml();
	function swf_fetch_xml($includeHeader = true, $tabLevel = 0, $nodeName = "swfHeader"){
		return $this->fetch_xml($includeHeader, $tabLevel, $nodeName);
	}
}


/**
* inspect swf files and get deep info
* build a framelist with tagList
* --- please doc methods ---
*/
class MKSwfInspector extends MKSwfInfo {

	var $frameList = array();	// array of SWFFrame

	var $tagReport;				// these members are useful
	var $offsetMap;				// ... to improve search/retrieving tags ...
	var $itemIDMap;				// ... by their offset/itemID

	// the constructor
	function MKSwfInspector($swfFileName = "", $swfWorkingDir = SERVER_MKFLASH){

		$this->swfWorkingDir = $swfWorkingDir;

		if(strlen($swfFileName)){
			parent::MKSwfInfo($swfFileName, $this->swfWorkingDir, false);
			$this->get_master_tags();
		}
	}

	//
	function get_frameList(){ return $this->frameList; }

	//
	function set_tagReport($tagReport) { $this->tagReport = $tagReport;	}
	function get_tagReport() { return $this->tagReport;	}

	//
	function set_offsetMap($offsetMap) {$this->offsetMap = $offsetMap; }
	function get_offsetMap() { return $this->offsetMap; }

	//
	function set_itemIDMap($itemIDMap) {$this->itemIDMap = $itemIDMap; }
	function get_itemIDMap() { return $this->itemIDMap; }

	//
	function get_master_tags(){

		$mkft = new MKFrameListTranslator($this->rawBody);
		$this->frameList = $mkft->get_frameList();
		$this->tagReport = $mkft->get_tagReport();
		$this->offsetMap = $mkft->get_offsetMap();
		$this->itemIDMap = $mkft->get_itemIDMap();

		return $this->frameList;
	}

	//
	function get_tagByOffset($offset){

		$offsetIndex = "x" .$offset;
		if(!isset($this->offsetMap[$offsetIndex])) return false;

		$tagRef = $this->offsetMap[$offsetIndex];
		$frameIndex = $tagRef["frameIndex"];
		$tagIndex = $tagRef["tagIndex"];

		$swfFrame = $this->frameList[$frameIndex];

		return $swfFrame->get_tagAt($tagIndex);
	}

	//
	function get_tagByItemID($itemID){

		$offsetID = "x" .$itemID;
		if(!isset($this->itemIDMap[$offsetID])) return false;

		$tagRef = $this->itemIDMap[$offsetID];
		$frameIndex = $tagRef["frameIndex"];
		$tagIndex = $tagRef["tagIndex"];

		$swfFrame = $this->frameList[$frameIndex];

		return $swfFrame->get_tagAt($tagIndex);
	}

	//
	function find_firstTagID($tagID, $frameNumber = -1){
		$th = $this->tagReport->find_tagHeadersByTagID($tagID, $frameNumber);
		if(!count($th)) return false;
		return $this->get_tagByOffset($th[0]["offset"]);
	}

	//
	function dump_tags_on_files($tagsDir = SERVER_MKTAGS, $flagCreateFolder = true) {


		$fCount = count($this->frameList);

		if($tagsDir == SERVER_MKTAGS || $flagCreateFolder){
			$tagsDir .= basename($this->swfFileName, ".swf") ."/";

			if(!file_exists($tagsDir)) mkdir($tagsDir, 0777);
		}

		$this->dump_headerData("", $tagsDir);


		for($i = 0; $i < $fCount; $i++){
			$frame = $this->frameList[$i];
			$tl = $frame->get_tagList();
			$k = 1;

			foreach($tl as $tag){
				$tag->save_to_file("", $tagsDir, $i + 1, $k++);
			}
		}
	}

	//
	function fetch_xml($includeHeader = true, $tabLevel = 0, $nodeName = "MKSwfReport", $includeHexData = false){

		$swfXHStr = parent::fetch_xml(false, $tabLevel + 2);

		$xmlStr = $includeHeader ? XML_HEADER : "";
		$pfx = get_xml_indent_row(++$tabLevel);
		$xmlStr .= $pfx ."<" .$nodeName ." ";
		$xmlStr .= "creationDate=\"" .date("Y.m.d") ."\" ";
		$xmlStr .= "creationTime=\"" .date("H:i:s") ."\" >";
		$pfx = get_xml_indent_row(++$tabLevel);

		$xmlStr .= $swfXHStr;

		$pfx = get_xml_indent_row(++$tabLevel);

		//return $xmlStr;

		$xmlStr .= $pfx . "<rootTimeline frameCount=\"" .count($this->frameList) ."\">";
		$i = 1;
		$pfx = get_xml_indent_row(++$tabLevel);

		foreach($this->frameList as $frame){

			if($frame->frame_is_empty()) continue;

			$xmlStr .= $pfx ."<frameItem number=\"" .$frame->get_frameNumber() ."\">";

			$tagList = $frame->get_tagList();
			$pfx = get_xml_indent_row(++$tabLevel);

			foreach($tagList as $tag){

				$tagID = $tag->get_tagID();
				$tagType = $tag->get_tagType();
				$buf = $tag->get_tagData();
				$obj = $tag;

				if($tagType == "ProductInfo"){
					$obj = new MKProductInfo($buf);
				}
				else if($tagType == "SetBackgroundColor"){
					$obj = new MKSetBackgroundColor($buf);
				}
				else if($tagID == MOVIECLIP){
					$obj = new MKMovieClip($buf);
				}
				else if($tagID == TEXT || $tagID == TEXT2){
					$obj = new MKStaticText($buf);
				}
				else if($tagID == TEXTFIELD){
					$obj = new MKTextField($buf);
				}
				else if($tagID == FONT2 || $tagID == FONT3){
					$obj = new MKFontContainer($buf);
				}
				else if($tagID == FLASHTYPE){
					$obj = new MKFontAlignZones($buf);
				}
				else if($tagID == TEXTSETTINGS){
					$obj = new MKCSMTextSettings($buf);
				}
				else if($tagType == "DefineFontName"){
					$obj = new MKFontName($buf);
				}
				else if($tagID == PLACEOBJECT2){
					$obj = new MKPlaceObject2($buf);
				}
				else if($tagID == PLACEOBJECT3){
					$obj = new MKPlaceObject3($buf);
				}
				else if($tagID == BUTTON || $tagID == BUTTON2){
					$obj = new MKButtonContainer($buf);
				}
				else if($tagType == "RemoveObject2"){
					$obj = new MKRemoveObject2($buf);
				}
				else if($tagType == "FrameLabel"){
					$obj = new MKFrameLabel($buf);
				}
				else if($tagType == "Protect"){
					$obj = new MKProtect($buf);
				}
				else if($tagID == LINKAGE){
					$obj = new MKExportAssets($buf);
				}
				else if($tagID == SOUND){
					$obj = new MKSoundContainer($buf);
				}
				else if($tagID == SOUND_SH || $tagID == SOUND_SH2){
					$obj = new MKSoundStreamHead($buf);
				}
				else if($tagType == "DefineButtonSound"){
					$obj = new MKButtonSound($buf);
				}
				else if($tagID == AS3SCENENAMES){
					$obj = new MKSceneNames($buf);
				}
				else if($tagID == AS3CLASSNAMES){
					$obj = new MKClassNames($buf);
				}

				//$nodeName = $obj->get_nodeName();
				$xmlStr .= $obj->fetch_xml(false, $tabLevel);
			}

			$pfx = get_xml_indent_row(--$tabLevel);
			$xmlStr .= $pfx ."</frameItem>\r\n";
		}

		$pfx = get_xml_indent_row(--$tabLevel);
		$xmlStr .= $pfx . "</rootTimeline>";
		$pfx = get_xml_indent_row(--$tabLevel);
		$xmlStr .= $pfx ."</" .$nodeName .">";

		//if($xh == "tags") $xml .= $this->close_xml();

		return $xmlStr;
	}
}


/**
* save an swf structure stored in php-data format
* --- please complete class description ---
*/
class MKSwfSerializer {

	var $swfHeader;
	var $frameList;

	function MKSwfSerializer($swfHeader, $frameList){
		$this->swfHeader = $swfHeader;
		$this->frameList = $frameList;
		$this->serialize_class();
	}

	function set_swfHeader($swfHeader) { $this->swfHeader = $swfHeader; }
	function get_swfHeader() { return $this->swfHeader; }

	function set_frameList($frameList) { $this->frameList = $frameList; }
	function get_frameList() { return $this->frameList; }

	function serialize_class(){

		$sfPath = get_filename_serialized($this->swfHeader["swfFileName"]);
		$fp = fopen($sfPath, "wb");

		//fwrite($fp, $strSerialized, strlen($strSerialized));
		$str = serialize($this->swfHeader);
		fwrite($fp, swf_dword(strlen($str)), 4);
		fwrite($fp, $str, strlen($str));
		$str = serialize($this->frameList);
		fwrite($fp, $str, strlen($str));

		fclose($fp);
	}
}

/**
* get an swf structure stored in php-data format
* --- please complete class description ---
*/
class MKSwfUnserializer {

	var $swfHeader;
	var $frameList;

	function MKSwfUnserializer($swfFileName){

		$sfPath = get_filename_serialized($swfFileName);
		$fp = fopen($sfPath, "rb");

		$strLength = fread($fp, 4);
		$ssLength = ui32dec($strLength);

		$str  = fread($fp, $ssLength);
		$this->swfHeader = unserialize($str);
		$str = fread($fp, filesize($sfPath) - $ssLength - 4);
		$this->frameList = unserialize($str);

		fclose($fp);
	}

	function get_swfHeader() { return $this->swfHeader; }
	function get_frameList() { return $this->frameList; }
}

/**
 * base class
 * unserialize and set working frame
 */
class MKSwfFrameEditor {

	var $workingFrame;
	var $mksu;				// unserialized object

	function MKSwfFrameEditor($swfFileName, $workingFrame = 1){

		$this->swfFileName = $swfFileName;
		$this->workingFrame = $workingFrame;
		$this->mksu = new MKSwfUnserializer($this->swfFileName);
	}

	function set_swfFileName($swfFileName){ $this->swfFileName = $swfFileName; }
	function get_swfFileName(){ return $this->swfFileName; }

	function set_workingFrame($workingFrame){ $this->workingFrame = $workingFrame; }
	function get_workingFrame(){ return $this->workingFrame; }
}


/**
* used to count items in a given frame
*  ---  please complete class description ---
*/
class MKSwfItemCounter extends MKSwfFrameEditor {

	var $itemCountlist = array();	// array of item counters

	function MKSwfItemCounter($swfFileName, $workingFrame = 1){

		parent::MKSwfFrameEditor($swfFileName, $workingFrame);
		$this->count_items();
	}

	function get_itemCountlist() { return $this->itemCountlist; }

	function count_items(){

		$frameList = array();
		$tagList = array();

		$frameList = $this->mksu->get_frameList();

		$swfFrame = $frameList[$this->workingFrame - 1];
		$tagList = $swfFrame->get_tagList();

		$itStr = "";
		foreach($tagList as $tag){
			$itStr .= $tag->get_tagType() .",";
		}

		$this->itemCountlist["actions"] = substr_count($itStr, ACTION_ITEM);
		$this->itemCountlist["shapes"] = substr_count($itStr, SHAPE_ITEM);
		$this->itemCountlist["movieclips"] = substr_count($itStr, MOVIECLIP_ITEM);
		$this->itemCountlist["buttons"] = substr_count($itStr, BUTTON_ITEM);
		$this->itemCountlist["images"] = substr_count($itStr, IMAGE_ITEM);
		$this->itemCountlist["videos"] = substr_count($itStr, VIDEO_ITEM);
		$this->itemCountlist["sounds"] = substr_count($itStr, SOUND_ITEM);
		$this->itemCountlist["fonts"] = substr_count($itStr, FONT_ITEM);

		$rwCount = count($tagList);
		foreach($this->itemCountlist as $k=>$v) $rwCount -= $v;

		$this->itemCountlist["rawtags"] = $rwCount;
	}
}

/**
 * takes a full list of item category in a given frame
 */
class MKSwfItemGrabber extends MKSwfInspector {

	var $itemList = array();	// array of item
	var	$rawFrameList = array();
	var $tagType = "";
	var $tagID = 0;
	var $searchTagID = 0;

	function MKSwfItemGrabber($swfFileName, $workingDir = SERVER_MKFLASH, $workingFrame = 1, $tagType = "", $tagID = array()){

		//parent::MKSwfFrameEditor($swfFileName, $workingFrame);
		if(strlen($workingDir)) $this->workingDir = $workingDir;
		$this->workingFrame = $workingFrame;

		parent::MKSwfInspector($swfFileName, $workingDir);

		if(strlen($tagType)){
		  $this->tagType = $tagType;
		  $this->fill_itemList();
		  return;
		}

		if($tagID != 0){
			$this->searchTagID = is_array($tagID) ? $tagID : array($tagID);
			$this->fill_itemList_by_tagID();
		}
	}

	function set_tagType($tagType){ $this->tagType = $tagType; }
	function get_tagType(){ return $this->tagType; }

	function get_itemList(){ return $this->itemList; }

	function set_rawFrameList($rawFrameList){ $this->rawFrameList = $rawFrameList; }
	function get_rawFrameList(){ return $this->rawFrameList; }

	function get_rawTagAt($tagIndex = 0, $refreshTagBody = true){

		if(!count($this->rawFrameList)){
			$rfig = new MKSwfRawFrameListGrabber($this->swfFileName, $this->swfWorkingDir);
			$this->rawFrameList = $rfig->get_rawFrameList();
		}

		if($tagIndex < count($this->rawFrameList))
			$swfTagObj = $this->rawFrameList[$tagIndex];
			//if($refreshTagBody) $swfTagObj->set_tagBody();
			return $swfTagObj;
	}

	function fill_itemList(){

		$frameList = array();
		$tagList = array();

		//$frameList = $this->mksu->get_frameList();

		$swfFrame = $this->frameList[$this->workingFrame - 1];
		$tagList = $swfFrame->get_tagList();

		foreach($tagList as $tag){

			$tagType = $tag->get_tagType();

			if(strpos($this->tagType, IMAGE_ITEM) !== false){

				if((strpos($tagType, $this->tagType) !== false || $tagType == JPEG_TABLE)){
					$this->add_item($tag);
				}
			}
		}
	}

	function add_item($tag){

		$flCount = count($this->itemList);

		// IMAGE_ITEM filter
		if($this->tagType == IMAGE_ITEM ||
		   $this->tagType == JPEG_TABLE){

			$tagType = $tag->get_tagType();
			$binData = $tag->get_tagBody();

			$bd = read_bitmapTag($tagType, $binData);
			$biObj = new BitmapItem($bd["id"],
									$bd["bitmapType"],
									$bd["bitmapWidth"],
									$bd["bitmapHeight"],
									$bd["bitDepth"],
									$bd["rawData"],
									$bd["jpegTable"],
									$bd["jpegData"],
									$bd["rgbData"],
									$bd["alphaData"],
									$bd["pixelData"],
									$bd["colorTable"],
									$this->swfFileName,
									$this->workingFrame);



			if($tagType != JPEG_TABLE) $this->itemList[$flCount] = $biObj;
		}
	}

	//
	function fill_itemList_by_tagID(){

		$frameList = array();
		$tagList = array();

		$swfFrame = $this->frameList[$this->workingFrame - 1];
		$tagList = $swfFrame->get_tagList();

		foreach($tagList as $tag){

			$tagID = $tag->get_tagID();

			foreach($this->searchTagID as $stid){
				if($tagID == $stid){
					$this->add_rawItem($tag);
				}
			}
		}
	}

	//
	function add_rawItem($rawTag){
		$ri = count($this->rawFrameList);
		$this->rawFrameList[$ri] = $rawTag;
	}

	function fetch_xml($includeHeader = true, $itemObject = true){

		$xmlStr = ($includeHeader) ? "<?xml version=\"1.0\"?>" : "";

		if($itemObject){
		}
		else{

			$xmlStr .= "\r\n<mungeList tagID=\"";
			$xmlStr .= $this->searchTagID;
			$xmlStr .="\">\r\n\t<swfFrame number=\"";
			$xmlStr .= $this->workingFrame;
			$xmlStr .= "\">";

			$k = 1;
			foreach($this->rawFrameList as $rawTag){

				$xmlStr .= "\r\n\t\t<tagItem number=\"";
				$xmlStr .= $k++;
				$xmlStr .= "\">\r\n\t\t\t<hexData>";
				$xmlStr .= hex_dump($rawTag->get_binData(), true);
				$xmlStr .= "</hexData>\r\n\t\t\t</tagItem>";
			}
			$xmlStr .= "\r\n</swfFrame>";
			$xmlStr .= "\r\n</mungeList>";
		}
		return $xmlStr;
	}
}



/**
 * takes a full list of item category in a given swf
 * it does not parse items
 */
class MKSwfItemDistiller extends MKSwfInspector {

	var $swfFileName = "";
	var $requiredTagList = array();	// array of item to distill
	var $distilledRFList = array();

	// the constructor
	function MKSwfItemDistiller($swfFileName, $requiredTagList = array()){

		if(strlen($swfFileName)){
			$this->swfFileName = $swfFileName;
			parent::MKSwfInspector($swfFileName);
		}

		if(count($requiredTagList)){
			$this->requiredTagList = $requiredTagList;
			if(count($this->frameList)) $this->distill();
		}
	}


	//
	function set_swfFileName($swfFileName) {
		$this->swfFileName = $swfFileName;
		parent::MKSwfInspector($swfFileName);
	}
	function get_swfFileName() { return $this->swffileName; }

	function set_tagType($tagType){ $this->tagType = $tagType; }
	function get_tagType(){ return $this->tagType; }

	function get_distilledRFList(){ return $this->distilledRFList; }

	function distill(){

		$frameCount = count($this->frameList);

		for($i = 0; $i < $frameCount; $i++){

			$frame = $this->frameList[$i]->get_tagList();

			$this->distilledRFList[$i] = array();

			foreach($frame as $tag){

				foreach($this->requiredTagList as $rt){

					$tagID = $tag->get_tagID();
					if($rt == $tagID)
						$this->add_item($tag, $i);
				}
			}
		}
	}

	//
	function add_item($tag, $frameIndex){

		$tidx = count($this->distilledRFList[$frameIndex]);
		$this->distilledRFList[$frameIndex][$tidx] = $tag;
	}

	//
	function get_tagAt($frameIndex, $index){
		if($frameIndex > count($this->distilledRFList)) return false;
		return $this->distilledRFList[$frameIndex - 1][$index];
	}

	//
	function get_count_report(){

		$dflCount = count($this->distilledRFList);
		$gcr = array();

		foreach($this->requiredTagList as $rt){

			$k = "tagCode_" .$rt;
			$gcr[$k]["totalCount"] = 0;
			$gcr[$k]["singleFrameCount"] = "";

			for($i = 0 ; $i < $dflCount; $i++){

				$tagList = $this->distilledRFList[$i];
				$fc = 0;

				if(count($tagList)){

					foreach($tagList as $tag){
						$tagID = $tag->get_tagID();
						if($rt == $tagID){
							$gcr[$k]["totalCount"]++;
							$fc++;
						}
					}
					$gcr[$k]["singleFrameCount"] .= $fc .",";
				}
				else {
					$gcr[$k]["singleFrameCount"] .= "0,";
				}
			}
		}

		return $gcr;
	}

	//
	function fetch_xml($includeHeader = true, $tabLevel = 0, $nodeName = "itemListDistiller"){

		$xmlStr = ($includeHeader) ? "<?xml version=\"1.0\"?>" : "";

		/*TODO: implement fetch_xml */
		return $xmlStr;
	}
}


/**
 * main class writer
 * --- please doc ---
 */
class MKSwf extends MKSwfInfo {

	var $headerTags = array();
	var $frameList = array();
	var $workingFrame = 1;
	var $tempSwf = "";
	var $swfData = "";
	var $swfDir = SERVER_MKTMP;
	var $rawBody = "";
	var $rawFrameList = array ();

	function MKSwf($swfInitialParam = SWF_DEFAULT_NAME,
					$swfVersion = SWF_DEFAULT_VERSION,
					$stageWidth = SWF_DEFAULT_STAGEWIDTH,
					$stageHeight = SWF_DEFAULT_STAGEHEIGHT,
					$fps = SWF_DEFAULT_FPS,
					$frameCount = 1,
					$backgroundColor = SWF_DEFAULT_BACKGROUNDCOLOR,
					$isCompressed = "no") {

		if(is_array($swfInitialParam)){

			parent::MKSwfHeader($swfInitialParam["swfFileName"],
									$swfInitialParam["swfVersion"],
									$swfInitialParam["stageWidth"],
									$swfInitialParam["stageHeight"],
									$swfInitialParam["fps"],
									$swfInitialParam["frameCount"],
									$swfInitialParam["backgroundColor"],
									$swfInitialParam["isCompressed"]);
		}
		else {
			parent::MKSwfHeader($swfInitialParam,
									$swfVersion,
									$stageWidth,
									$stageHeight,
									$fps,
									$frameCount,
									$backgroundColor,
									$isCompressed);
		}
	}

	//
	function set_headerTags($headerTags = array()){
		if(is_array($headerTags) && count($headerTags))
			$this->headerTags = $headerTags;
	}

	//
	function get_headerTags() { return $this->headerTags; }


	//
	function get_frameCount(){
		return count($this->frameList);
	}

	//
	function set_frameList($frameList) { $this->frameList = $frameList; }
	function get_frameList() { return $this->frameList; }

	//
	function set_workingFrame($workingFrame) { $this->workingFrame = $workingFrame; }
	function get_workingFrame() { return $this->workingFrame; }

	//
	function set_swfDir($swfDir) { $this->swfDir = $swfDir; }
	function get_swfDir() { return $this->swfDir; }

	//
	function set_rawBody($rawBody){ $this->rawBody = $rawBody; }
	function get_rawBody(){ return $this->rawBody; }

	//
	function set_swfOutFileSize($swfOutFileSize) { $this->swfOutFileSize = $swfOutFileSize; }
	function get_swfOutFileSize() { return $this->swfOutFileSize; }

	//
	function get_swfData() { return $this->swfData; }

	//
	function set_rawFrameList($rawFrameList) { $this->rawFrameList = $rawFrameList; }
	function get_rawFrameList() { return $this->rawFrameList; }

	//
	function grab_rawFrameList(){
		$mkrg = new MKSwfRawFrameListGrabber($this->swfFileName);
		$this->rawFrameList = $mkrg->grab_rawFrameList();
	}

	//
	function create_tempSwf(){ $this->tempSwf = get_tmpFileName("ts"); }

	//
	function add_header_tagData($tagData) {
		$this->headerTags[] = $tagData;
	}

	// note that frameNumber request start from 1
	function add_tagData($tagData, $frameNumber = 1){

		if($frameNumber <= 0) $frameNumber = $this->workingFrame;
		$this->workingFrame = $frameNumber;

		$fi = max($this->workingFrame - 1, 0);				// frame index

		if(!isset($this->frameList[$fi])){ // start new tagList in case of missing
			$this->frameList[$fi] = array();
		}
		$ti = count($this->frameList[$fi]);

		$this->frameList[$fi][$ti] = $tagData;
		$this->workingFrame = count($this->frameList);
	}

	//
	function add_tagData_from_file($tagFN = "", $tagDir = "", $frameNumber = 0){
		$tagPath = $tagDir .$tagFN;
		if(file_exists($tagPath)){
			$tagIn = fopen($tagPath, "rb");
			$tagData = fread($tagIn, filesize($tagPath));
			fclose($tagIn);
			$this->add_tagData($tagData, $frameNumber);
		}
		else return false;
	}

	//
	function add_frame($frameType = SIMPLE_FRAME, $frame = ""){

		$flCount = count($this->frameList);

		if($frameType == SIMPLE_FRAME){
			$this->frameList[$flCount] = array();
		}
		else if($frameType == OBJECT_FRAME){
			if(get_class($frame))
				$this->frameList[$flCount] = $frame;
			else $this->frameList[$flCount] = new SWFFrame();
		}
		else if($frameType == RAW_FRAME){
			$this->frameList[$flCount] = $frame;
		}

		$this->workingFrame = count($this->frameList);
	}

	// save swf content to file
	function swf_output($savingOpt = OUTPUT_FROM_FRAMELIST_SIMPLE){ // save swf
		$this->frameCount = count($this->frameList);
		$this->swfData = do_swf_output($this, $savingOpt);
	}

	// alias of swf_output
	function save($savingOpt = OUTPUT_FROM_FRAMELIST_SIMPLE){ // save swf
		$this->swf_output($savingOpt);
	}

	// build swfData without saving to file
	function compile() {
		$this->swfData = do_swf_output($this, OUTPUT_FROM_FRAMELIST_SIMPLE, false);
		return $this->swfData;
	}

	// replace tag in frameList
	function replace_tag($tagIndex, $swfTag, $frameNumber = -1){

		if($frameNumber > 0) $this->workingFrame = $frameNumber;
		$wf = $this->workingFrame - 1;

		$this->rawFrameList[$wf][$tagIndex] = $swfTag;
	}

	// sets all swf_header but swfFileName
	function set_swfHeader($swfHeader){

		$this->set_swfVersion($swfheader->get_swfVersion());
		$this->set_stageWidth($swfheader->get_frameCount());
		$this->set_stageHeight($swfheader->get_frameCount());
		$this->set_fps($swfheader->get_frameCount());
		$this->set_frameCount($swfheader->get_frameCount());
		$this->set_backgroundColor($swfheader->get_frameCount());
		$this->set_isCompressed($swfheader->get_frameCount());
	}

	//
	function load_swf_from_file($swfFileName = "", $swfDir = SERVER_MKFLASH) {

	}
}

/**
 * @private
 * used to translate a framelist from binary stored data to mk structure
 * and viceversa
 */
class MKFrameListTranslator {

	var $frameList = array();
	var $rawBody = "";
	var $tagReport;
	var $offsetMap = array();
	var $itemIDMap = array();

	// the constructor
	function MKFrameListTranslator($rawBody = ""){

		$this->rawBody = $rawBody;
		$this->tagReport = new MKTagReport();

		if(strlen($this->rawBody)) $this->rawBody_to_frameList();
	}

	//
	function set_frameList($frameList){ $this->frameList = $frameList; }
	function get_frameList() { return $this->frameList; }

	//
	function set_rawBody($rawBody) { $this->rawBody = $rawBody; }
	function get_rawBody() { return $this->rawBody; }

	//
	function set_tagReport($tagReport) {$this->tagReport = $tagReport; }
	function get_tagReport() { return $this->tagReport; }

	//
	function set_offsetMap($offsetMap) {$this->offsetMap = $offsetMap; }
	function get_offsetMap() { return $this->offsetMap; }

	//
	function set_itemIDMap($itemIDMap) {$this->itemIDMap = $itemIDMap; }
	function get_itemIDMap() { return $this->itemIDMap; }

	//
	function rawBody_to_frameList(){

		/* here we are ready to analyze */
		$tfSize = strlen($this->rawBody);

		$tagOffset = 0;
		$flIndex = 0;
		$this->frameList[$flIndex] = new SWFFrame(1);

		while($tagOffset < $tfSize){

			$tagHData = read_tag_header_data(substr($this->rawBody, $tagOffset, 10), $tagOffset);
			if($tagHData["tagID"] == PLACEOBJECT2){
				$poIdx = $tagOffset + $tagHData["tagSL"];
				$tagHData["poFlags"] = read_placeObject2_flags($this->rawBody[$poIdx]);
			}

			$currentOffset = $tagOffset;
			$tagOffset += $tagHData["tagOffset"];
			$tagType = $tagHData["tagType"];

			if($tagType == "ShowFrame") {

				$this->frameList[++$flIndex] = new SWFFrame($flIndex + 1);
			}
			else{

				if($tagType == "End"){

					array_pop($this->frameList);
				}
				else {

					$tagIndex = $this->frameList[$flIndex]->get_tagCount();

					$this->tagReport->add_tagHeaderAt($tagHData, $flIndex);

					$omKey = "x" .$tagHData["offset"];
					$this->offsetMap[$omKey] = array();
					$this->offsetMap[$omKey]["frameIndex"] = $flIndex;
					$this->offsetMap[$omKey]["tagIndex"] = $tagIndex;

					if($tagHData["itemID"] > 0){
						$imKey = "x" .$tagHData["itemID"];
						$this->itemIDMap[$imKey] = array();
						$this->itemIDMap[$imKey]["frameIndex"] = $flIndex;
						$this->itemIDMap[$imKey]["tagIndex"] = $tagIndex;
					}

					$tagData = substr($this->rawBody, $currentOffset, $tagHData["tagOffset"]);
					$this->frameList[$flIndex]->add_tag($tagData, $tagHData);
				}
			}
		}

		return $this->frameList;
	}

	//
	function frameList_to_rawBody(){

		$this->rawBody = "";
		$k = 0;

		foreach ($this->frameList as $swfFrame){

			$tagList = $swfFrame->get_tagList();

			foreach ($tagList as $tag){

				$swfTagBody = $tag->get_binData();
				$swfTLength = strlen($swfTagBody);

				if($swfTLength > 63) $swfTagHeader = SWFTag_long_header($tag->get_tagID(), $swfTLength);
				else $swfTagHeader = SWFTag_short_header($tag->get_tagID(), $swfTLength);
				$this->rawBody .= $swfTagHeader .$swfTagBody;
			}

			$this->rawBody .= swf_showFrame();
			$k++;
		}

		$this->rawBody .= SWFTag_end();

		return $this->rawBody;
	}
}

/**
 * find a reference and binData
 * of an item in given swf
 */
class MKSwfItemFinder extends MKSwfFrameEditor {

	var $itemID;
	var $binData;
	var $itemType;
	var $frameList;

	// class constructor
	function MKSwfItemFinder($swfFileName = "",
							$workingFrame = 1,
							$itemID = 1,
							$itemType = IMAGE_ITEM){

		parent::MKSwfFrameEditor($swfFileName, $workingFrame);

		$this->itemID = $itemID;
		$this->itemType = $itemType;
		$this->frameList = $this->mksu->get_frameList();
	}

	function set_itemID($itemID){ $this->itemID = $itemID; }
	function get_itemID(){ return $this->itemID; }

	function set_itemType($itemType){ $this->itemType = $itemType; }
	function get_itemType(){ return $this->itemType; }

	function set_binData($binData){ $this->binData = $binData; }
	function get_binData(){ return $this->binData; }

	// find an item in workingFrame
	function find_item_in_frame($wf = -1, $iid = -1){

		if($wf == -1) $wf = $this->workingFrame;
		else $this->workingFrame = $wf;

		if($iid == -1) $iid = $this->itemID;
		else $this->itemID = $iid;

		$itemPosition["frameNumber"] = $wf;
		$itemPosition["itemNumber"] = 0;
		$itemPosition["binData"] = "";

		$swfFrame = $this->frameList[$wf - 1];
		$tagList = $swfFrame->get_tagList();

		foreach($tagList as $tag){

			$tagType = $tag->get_tagType();

			if(strpos($tagType, $this->itemType) !== false) {

				if($this->itemID == $tag->get_itemID()){
					$itemPosition["binData"] = $tag->get_binData();
					return $itemPosition;
				}
			}

			$itemPosition["itemNumber"]++ ;
		}


		$itemPosition["itemNumber"] = -1;
		return $itemPosition; // item not found
	}

	// find an item in the whole frameList
	function find_item_in_frameList($maxFrameCount = -1){

		$itemPosition = array();
		$itemPosition["frameNumber"] = 1;
		$itemPosition["itemNumber"] = 0;
		$itemPosition["binData"] = "";

		if($maxFrameCount < 0) $maxFrameCount = count($this->frameList);

		$k = 1;

		foreach($this->frameList as $swfFrame){

			$tagList = $swfFrame->get_tagList();

			foreach($tagList as $tag){

				$tagType = $tag->get_tagType();

				//if(strlen($this->itemType) && strpos($tagType, $this->itemType) !== false) {

					if($this->itemID == $tag->get_itemID()){
						$itemPosition["tagData"] = $tag->get_buf();
						return $itemPosition;
					}
				//}

				$itemPosition["itemNumber"]++ ;
			}

			$itemPosition["frameNumber"]++ ;
			if($k++ > $maxFrameCount) break;
		}

		$itemPosition["frameNumber"] = -1;
		$itemPosition["itemNumber"] = -1;
		$itemPosition["tagData"] = "";
		return $itemPosition; // item not found
	}

	//
	function find_first_tagID($tagID, $workingFrame = -1){

		$wf = ($workingFrame > 0) ? $workingFrame : $this->workingFrame;
		$swfFrame = $this->frameList[$wf - 1];
		$tagList = $swfFrame->get_tagList();

		foreach($tagList as $tag){

			$ti = $tag->get_tagID();

			if($tagID == $ti) return $tag;
		}

		return -1; // data not found
	}

	//
	function get_itemAt($itemID = 1, $frameNumber = 1){

		$swfFrame = $this->frameList[$frameNumber - 1];
		$tagList = $swfFrame->get_tagList();

		foreach($tagList as $tag){

			$iid = $tag->get_itemID();

			if($iid == $itemID) return $tag;
		}

		return -1; // item not found
	}
}


/**
 * retrieve an array of frames
 * each frame is an array whose items are $rawTagData
 * ALL tags are included (showFrame, end and so on)
 */
class MKSwfRawFrameListGrabber extends MKSwfInfo {

	var $rawFrameList = array();

	function MKSwfRawFrameListGrabber($swfFileName = "", $swfWorkingDir = ""){

		parent::MKSwfInfo($swfFileName, $swfWorkingDir);
		$this->grab_rawFrameList();
	}

	function set_rawFrameList($rawFrameList) {$this->rawFrameList = $rawFrameList; }
	function get_rawFrameList(){ return $this->rawFrameList; }

	function grab_rawFrameList(){

		/* here we are ready to analyze */
		$tfSize = strlen($this->rawBody);
		$tagOffset = 0;
		$oldTagOffset = 0;
		$tagHData = array();
		$tagHData["tagID"] = -1;
		$tagHData["tagLength"] = 0;
		$tagHData["tagOffset"] = 0;

		$fli = 0;
		$rti = 0;
		$this->rawFrameList[$fli] = array();

		while($tagOffset < $tfSize){

			$tagHeader = substr($this->rawBody, $tagOffset, 10);
			$tagHData = read_tag_header_data($tagHeader, $tagOffset);

			$tagOffset += $tagHData["tagOffset"];
			$tagType = $tagHData["tagType"];

			if($tagType == "ShowFrame") {

				$fli = count($this->rawFrameList);
				$rti = 0;
				$this->rawFrameList[] = array();
			}
			else{

				$rawTagData = substr($this->rawBody, $oldTagOffset, $tagOffset - $oldTagOffset);
				$this->rawFrameList[$fli][] = $rawTagData;
				$rtIndex = count($this->rawFrameList[$fli]) - 1;
			}

			$oldTagOffset = $tagOffset;
		}

		$fli = count($this->rawFrameList);
		//$rti = count($this->rawFrameList[$fli]);
		//array_pop($this->rawFrameList[$fli - 1]);
		array_pop($this->rawFrameList);
		return $this->rawFrameList;
	}
}


/**
 * MKTagReport
 * is a simple associative array wrapper
 * tReport items are frame
 * each frame contains a collection of tags header data
 */
class MKTagReport{

	var $tReport = array();

	// the constructor
	function MKTagReport(){
	}

	//
	function set_tagReport($tReport) { $this->tReport = $tReport; }
	function get_tagReport() { return $this->tReport; }

	//
	function add_tagHeaderAt($tagHeader = array(), $frameIndex = 0){

		if(!isset($this->tReport[$frameIndex])){

			$fCount = count($this->tReport);
			for($i = $fCount; $i <= $frameIndex; $i++){
				if(!isset($this->tReport[$i]))
					$this->tReport[$i] = array();
			}
		}

		$fiIdx = count($this->tReport[$frameIndex]);
		$this->tReport[$frameIndex][$fiIdx] = $tagHeader;
	}

	//
	function get_frameReport($frameIndex = 0){
		if(count($this->tReport) <= $frameIndex) return false;
		return $this->tReport[$frameIndex];
	}

	//
	function get_tagCount(){ return count($this->tReport); }

	// frameIndex -1 means, search the whole main timeline
	function find_tagHeadersByTagID($tagID, $frameIndex = -1){

		if(!is_array($tagID)){
			if(!$tagID) return array();
			$tagID = array($tagID);
		}

		$k = 0;
		$fCount = count($this->tReport);

		if($fCount < $frameIndex) return false;

		$tagHeaders = array();

		if($frameIndex > -1){
			$k = $frameIndex;
			$fCount = $k;
		}

		$tidCount = count($tagID);

		for($i = $k; $i < $fCount; $i++){

			if(!count($this->tReport[$i])) continue;

			$fReport = $this->tReport[$i];

			foreach($fReport as $th){

				for($j = 0; $j < $tidCount; $j++){

					$tid = $tagID[$j];

					if($th["tagID"] == $tid){

						$th["frame"] = $i + 1;
						$tagHeaders[] = $th;
					}
				}
			}
		}

		return $tagHeaders;
	}

	//
	function find_tagHeadersByTagType($tagType, $frameIndex = -1){

		if(!is_array($tagType)){

			if(!strlen($tagType)) return array();
			$tagType = array($tagType);
		}

		$tagID = array();
		foreach($tagType as $t) $tagID[] = get_tagID($t);

		return $this->find_tagHeadersByTagID($tagID, $frameIndex);
	}

	function find_tagHeadersByTagName($tagName = "", $frameIndex = -1){
		return $this->find_tagHeadersByTagType($tagName, $frameIndex);
	}
	//
	function find_tagHeaderByItemID($itemID){

		$tagHeader = array();
		$fCount = count($this->tReport);

		for($i = 0; $i < $fCount; $i++){

			if(!isset($this->tReport[$i])) continue;

			$fReport = $this->tReport[$i];

			foreach($fReport as $th){

				if(isset($th["itemID"])){

					if($th["itemID"] == $itemID){
						$th["frame"] = $i + 1;
						$tagHeader = $th;
						break;
					}
				}
			}
		}

		return $tagHeader;
	}


	//
	function find_tagHeaderByOffset($offset){

		$tagHeader = array();
		$fCount = count($this->tReport);

		for($i = 0; $i < $fCount; $i++){

			if(!isset($this->tReport[$i])) continue;

			$fReport = $this->tReport[$i];

			foreach($fReport as $th){

				if(isset($th["offset"])){

					if($th["offset"] == $offset){
						$th["frame"] = $i + 1;
						$tagHeader = $th;
						break;
					}
				}
			}
		}

		return $tagHeader;
	}
}

/**
 * save to file tag content
 * usage: instantiate the class giving swfFilName and optional paramters
 * if enough data is given then autosave
 * useful method is set_tag, it allows to dump data after passing a valid
 * SWFTag object
 */
class MKTagDumper {

	var $tagData = "";
	var $tagObj;
	var $swfFileName = "";
	var $tagFileName = "";
	var $tagDir = SERVER_MKTAGS;


	// the constructor, swfFileName is mandatory
	function MKTagDumper($swfFileName, $tagData = "", $tagFileName = "", $tagDir = SERVER_MKTAGS){

		$this->swfFileName = $swfFileName;
		$this->tagData = $tagData;
		$this->tagFileName = $tagFileName;
		$this->tagDir = $tagDir;

		$this->tagObj = new SWFTag();

		if(strlen($tagData)){
			$this->dump_tagData();
			$this->tagObj->set_tagData($this->tagData);
		}
	}

 	//
	function set_swfFileName($swfFileName) { $this->swfFileName = $swfFileName;}
	function get_swfFileName() { return $this->swfFileName; }

	//
	function set_tagData($tagData, $dumpData = false) {

		$this->tagObj = new SWFTag();
		$this->tagObj->set_tagData($this->tagData);
		$this->tagData = $tagData;
		if($dumpData) $this->dump_tagData();
	}
	function get_tagData() { return $this->tagData; }

 	//
	function set_tagFileName($tagFileName) { $this->tagFileName = $tagFileName;}
	function get_tagFileName() { return $this->tagFileName; }

	//
	function set_tagDir($tagDir) { $this->tagDir = $tagDir; }
	function get_tagDir() { return $this->tagDir; }

	//
	function set_tagObj($tagObj) {
		$this->tagObj = $tagObj;
		$this->tagData = $tagObj->get_tagData();
	}
	function get_tagOjb() { return $this->tagObj; }

	// alias of set[get]_tagObj
	function set_tag($tagObj){
	 	$this->set_tagObj($tagObj);
	}
	function get_tag() { return $this->tag; }


	//
	function dump_tagData($tagFileName = "", $tagDir = ""){

		if(strlen($tagFileName)) $this->tagFileName = $tagFileName;
		if(strlen($tagDir)) $this->tagDir = $tagDir;

		if(!strlen($this->tagFileName)){

			if(!strlen($this->tagData)) return false;

			$fn = substr(basename($this->swfFileName, ".swf"), 0, 22);
			$tid = $this->tagObj->get_tagID();
			$id = has_itemID($tid) ? "_" .$this->tagObj->get_itemID() : "";
			$this->tagFileName = $fn ."_" .get_tagName($tid) .$id .".tag";
			$tagPath = $this->tagDir .$this->tagFileName;
			$tagOut = fopen($tagPath, "wb");
			fwrite($tagOut, $this->tagData, strlen($this->tagData));
			fclose($tagOut);
		}
	}
}


//----------------------------------------- end of MKclasses
?>
